using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using MPMovieCatalog.Domain;
using MPMovieCatalog.Exception;
using MPMovieCatalog.Forms.Grid;
using MPMovieCatalog.Service;
using MPMovieCatalog.Util;
using MPMovieCatalog.Util.Grabber;
using log4net;

namespace MPMovieCatalog.Forms
{
	public partial class ImportFilesForm : Form
	{
		private DataGridViewMultiColumnComboColumn m_matchedMoviesColumn;

        private int m_counter = 0;

        private List<MoviePicture> m_coverArts = new List<MoviePicture>();
		
		public ImportFilesForm()
		{
			InitializeComponent();
			
			splitContainer.Panel2Collapsed = true;

			m_matchedMoviesColumn = new DataGridViewMultiColumnComboColumn();
			m_matchedMoviesColumn.CellTemplate = new DataGridViewMultiColumnComboCell();
			m_matchedMoviesColumn.DataPropertyName = "SelectedMovie";
            m_matchedMoviesColumn.HeaderText = ResourceUtils.GetString("filesImport", 9);
			m_matchedMoviesColumn.Name = "matchedMoviesColumn";
			m_matchedMoviesColumn.Width = 200;
			m_matchedMoviesColumn.SortMode = DataGridViewColumnSortMode.NotSortable;
			
			m_matchedMoviesColumn.Columns.Add(new DataGridViewMultiColumnComboColumn.Column("Title", 1, 400));
			m_matchedMoviesColumn.Columns.Add(new DataGridViewMultiColumnComboColumn.Column("Script", 1, 200));
			m_matchedMoviesColumn.DisplayMember = "Title";
			m_matchedMoviesColumn.ValueMember = "Self";
			
			m_matchedMoviesColumn.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton;
			
			filesGridView.Columns.Remove("matchedMoviesColumn");
			filesGridView.Columns.Insert(2, m_matchedMoviesColumn);
            SetStatus(string.Empty, false);

            UpdateUI();
		}
		
		public ArrayList Files 
		{
			set
			{

				ArrayList importFiles = new ArrayList();
				foreach (ShareFile file in value)
				{
					importFiles.Add(new ImportFile(file));
				}
				
                IBindingList datasource = new SortableBindingList<ImportFile>(importFiles);
                bindingSource.DataSource = datasource;

                statusTotalCountLabel.Text = string.Format(ResourceUtils.GetString("filesImport", 10), importFiles.Count);
                statusSelectedCountLabel.Text = string.Format(ResourceUtils.GetString("filesImport", 11), importFiles.Count);
			}
		}
		
		void SearchToolButtonClick(object sender, EventArgs e)
		{
			List<IFetchable> moviesToFetch = new List<IFetchable>();
			foreach (ImportFile importFile in bindingSource)
			{
				if (importFile.Import)
				{
					moviesToFetch.Add(importFile);
				}
			}
			
			Fetcher fetcher = new Fetcher(moviesToFetch);
            using (ProgressWorker progressWorker = new ProgressWorker(fetcher))
            {
                progressWorker.Start();
            }
			
			foreach (DataGridViewRow row in filesGridView.Rows)
			{
				List<FetchedMovie> fetchedMovies = ((ImportFile)row.DataBoundItem).FetchedMovies;
				
				DataGridViewMultiColumnComboCell fetchedMoviesCell = (DataGridViewMultiColumnComboCell)row.Cells["matchedMoviesColumn"];
				fetchedMoviesCell.DataSource = fetchedMovies;
				
				if (fetchedMovies != null && fetchedMovies.Count > 0)
				{
					fetchedMoviesCell.Value = fetchedMovies[0];
				}
			}
			
			DisplayDetails();
		}
		
		void AddSelectedToolButtonClick(object sender, EventArgs e)
		{
            List<ImportFile> moviesToAdd = new List<ImportFile>();
            foreach (ImportFile importFile in bindingSource)
            {
                if (importFile.Import && importFile.SelectedMovie != null)
                {
                    moviesToAdd.Add(importFile);
                }
            }

            Adder adder = new Adder(moviesToAdd);
            using (ProgressWorker progressWorker = new ProgressWorker(adder))
            {
                progressWorker.Start();
            }
            RefreshList();
		}
		
		void CheckToolMenuItemClick(object sender, EventArgs e)
		{
			foreach (DataGridViewRow row in filesGridView.Rows)
			{
				DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)row.Cells["selectColumn"];
				cell.Value = ((ToolStripMenuItem)sender).Name.Equals(checkAllToolMenuItem.Name);
			}

            UpdateSelectedCount();
		}
		
		void PreviewToolButtonCheckStateChanged(object sender, EventArgs e)
		{
			splitContainer.Panel2Collapsed = !previewToolButton.Checked;
			DisplayDetails();
		}
		
		void FilesGridViewRowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
		{
			for (int i = 0; i < e.RowCount; i++)
			{
				DataGridViewRow row = filesGridView.Rows[e.RowIndex + i];
					
				List<FetchedMovie> fetchedMovies = ((ImportFile)row.DataBoundItem).FetchedMovies;
				
				DataGridViewMultiColumnComboCell fetchedMoviesCell = (DataGridViewMultiColumnComboCell)row.Cells["matchedMoviesColumn"];
				fetchedMoviesCell.DataSource = fetchedMovies;
			}
		}
		
		void FilesGridViewSelectionChanged(object sender, EventArgs e)
		{
			DisplayDetails();
		}	
		
		void FilesGridViewCellValueChanged(object sender, DataGridViewCellEventArgs e)
		{
			if (e.ColumnIndex == matchedMoviesColumn.Index)
			{
				DisplayDetails();
            }
            else if (e.ColumnIndex == selectColumn.Index)
            {
                UpdateSelectedCount();
            }
		}
		
		void FilesGridViewCurrentCellDirtyStateChanged(object sender, EventArgs e)
		{
			if (filesGridView.IsCurrentCellDirty)
		    {
		        filesGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
		    }
		}
		
		private void DisplayDetails() {
            m_coverArts.Clear();
            coverArtComboBox.DataSource = null;
			coverArtComboBox.Enabled = false;
			webBrowser.DocumentText = string.Empty;

			if (previewToolButton.Checked && filesGridView.SelectedRows != null && filesGridView.SelectedRows.Count > 0) {
                DataGridViewRow row = filesGridView.SelectedRows[0];
				FetchedMovie fetchedMovie = ((ImportFile)row.DataBoundItem).SelectedMovie;

                if (fetchedMovie != null)
                {
                    m_counter = 2;

                    this.Cursor = Cursors.WaitCursor;
                    splitContainer.Enabled = false;
                    toolStrip.Enabled = false;

                    SetStatus(string.Format(ResourceUtils.GetString("filesImport", 12), fetchedMovie.Title), true);

                    if (!movieInfoBackgroundWorker.IsBusy)
                    {
                        movieInfoBackgroundWorker.RunWorkerAsync(fetchedMovie);
                    }
                    if (!coverArtsBackgroundWorker.IsBusy)
                    {
                        coverArtsBackgroundWorker.RunWorkerAsync(fetchedMovie);
                    }
                }
            }
			
        }

        private void CoverArtsBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = (e.Argument as FetchedMovie).CoverArts;
        }

        private void CoverArtsBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                List<MoviePicture> coverArts = e.Result as List<MoviePicture>;
                if (coverArts != null && coverArts.Count > 0)
                {
                    m_coverArts.AddRange(coverArts);
                }
            }
            AfterRunWorkerCompleted();
        }

        private void MovieInfoBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = (e.Argument as FetchedMovie).MovieInfo;
        }

        private void MovieInfoBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                MovieInfo movieInfo = e.Result as MovieInfo;
                if (movieInfo != null)
                {
                    webBrowser.DocumentText = MPMovieCatalog.Util.TemplateUtils.TransformMovie(movieInfo, null);

                    if (!string.IsNullOrEmpty(movieInfo.PictureFileName))
                    {
                        m_coverArts.Insert(0, new MoviePicture("default", string.Empty, movieInfo.PictureFileName));
                    }
                }
            }
            AfterRunWorkerCompleted();
        }

        private void AfterRunWorkerCompleted()
        {
            m_counter--;

            if (m_counter == 0)
            {
                if (m_coverArts.Count > 0)
                {
                    coverArtComboBox.Enabled = true;
                    coverArtComboBox.DataSource = m_coverArts;
                    coverArtComboBox.SelectedIndex = -1;
                }

                splitContainer.Enabled = true;
                toolStrip.Enabled = true;

                SetStatus(string.Empty, false);
                this.Cursor = Cursors.Arrow;
            }
        }
		
		void CoverArtComboBoxSelectionChangeCommitted(object sender, EventArgs e)
		{
            Cursor = Cursors.WaitCursor;
            
			if (filesGridView.SelectedRows != null && filesGridView.SelectedRows.Count > 0) {
				MoviePicture coverArt =  coverArtComboBox.SelectedItem as MoviePicture;
	            if (string.IsNullOrEmpty(coverArt.FileName))
	            {
                    SetStatus(string.Format(ResourceUtils.GetString("filesImport", 13), coverArt.URL), true);
                    coverArt.FileName = MPMovieCatalog.Util.Utils.DownloadImage(coverArt.URL);
                    SetStatus(string.Empty, false);
	            }
	            
	            DataGridViewRow row =  filesGridView.SelectedRows[0];
				FetchedMovie fetchedMovie = ((ImportFile)row.DataBoundItem).SelectedMovie;
				fetchedMovie.MovieInfo.PictureFileName = coverArt.FileName;
				
	            webBrowser.DocumentText = MPMovieCatalog.Util.TemplateUtils.TransformMovie(fetchedMovie.MovieInfo, null);
            }
            Cursor = Cursors.Arrow;
		}


        private void refreshToolButton_Click(object sender, EventArgs e)
        {
            RefreshList();
        }

        private void RefreshList()
        {
            SetStatus(ResourceUtils.GetString("filesImport", 14), true);
            Cursor = Cursors.WaitCursor;
            IMovieService movieService = MovieServiceFactory.getMovieService();
            this.Files = movieService.GetNewFiles();
            Cursor = Cursors.Arrow;
            SetStatus(string.Empty, false);
        }

        private void SetStatus(string status, bool progressVisible)
        {
            statusLabel.Text = status;
            statusProgressBar.Visible = progressVisible;
            statusStrip.Update();
        }

        private void UpdateSelectedCount()
        {
            int selectedCount = 0;
            foreach (DataGridViewRow row in filesGridView.Rows)
            {
                DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)row.Cells["selectColumn"];
                selectedCount = (bool)cell.Value ? selectedCount + 1 : selectedCount;
            }
            statusSelectedCountLabel.Text = string.Format(ResourceUtils.GetString("filesImport", 11), selectedCount);
        }

        private void UpdateUI()
        {
            this.Text = ResourceUtils.GetString("filesImport", 0);
            refreshToolButton.ToolTipText = ResourceUtils.GetString("filesImport", 1);
            checkToolButton.ToolTipText = ResourceUtils.GetString("filesImport", 2);
            checkAllToolMenuItem.Text = ResourceUtils.GetString("filesImport", 3);
            uncheckAllToolMenuItem.Text = ResourceUtils.GetString("filesImport", 4);
            searchToolButton.ToolTipText = ResourceUtils.GetString("filesImport", 5);
            addSelectedToolButton.ToolTipText = ResourceUtils.GetString("filesImport", 6);
            previewToolButton.ToolTipText = ResourceUtils.GetString("filesImport", 7);
            fileNameColumn.HeaderText = ResourceUtils.GetString("filesImport", 8);
            m_matchedMoviesColumn.HeaderText = ResourceUtils.GetString("filesImport", 9);
        }


        private class ImportFile : IFetchable
        {
            private List<FetchedMovie> m_fetchedMovies = new List<FetchedMovie>();

            public ImportFile(ShareFile file)
            {
                Import = true;
                File = file;
            }

            public bool Import { get; set; }

            public string Name
            {
                get
                {
                    return File != null ? File.Name : string.Empty;
                }
            }

            public string Path
            {
                get
                {
                    return File != null ? File.Path : string.Empty;
                }
            }

            public ShareFile File { get; set; }

            public string Title
            {
                get
                {
                    return File != null ? System.IO.Path.GetFileNameWithoutExtension(File.Name) : string.Empty;
                }
            }

            public FetchedMovie SelectedMovie { get; set; }

            public MoviePicture SelectedCoverArt { get; set; }

            public List<FetchedMovie> FetchedMovies
            {
                get { return m_fetchedMovies; }
                set { m_fetchedMovies = value; }
            }

            public void AddFetchedMovie(FetchedMovie fetchedMovie)
            {
                m_fetchedMovies.Add(fetchedMovie);
            }

            public void AddFetchedMovies(List<FetchedMovie> fetchedMovies)
            {
                m_fetchedMovies.AddRange(fetchedMovies);
            }
        }

        private class Adder : IWorkable
        {
            private static readonly ILog log = LogManager.GetLogger(typeof(Adder));

            public Adder(List<ImportFile> moviesToAdd)
            {
                MoviesToAdd = moviesToAdd;
            }

            public List<ImportFile> MoviesToAdd { get; set; }

            public string Title
            {
                get { return ResourceUtils.GetString("filesImport", 15); }
            }

            public bool IsCancelled { get; set; }

            public string DoWork(ProgressWorker worker)
            {
                try
                {
                    worker.OnProgress(0, ResourceUtils.GetString("filesImport", 20));

                    int realAdded = 0;
                    if (MoviesToAdd != null && MoviesToAdd.Count > 0)
                    {
                        IMovieService movieService = MovieServiceFactory.getMovieService();

                        int step = 0;
                        int itemNumber = 1;
                        foreach (ImportFile importFile in MoviesToAdd)
                        {
                            if (worker.CancellationPending)
                            {
                                IsCancelled = true;
                                break;
                            }

                            if (importFile.SelectedMovie != null)
                            {
                                worker.OnProgress(GetPercent(step++), string.Format(ResourceUtils.GetString("filesImport", 16), importFile.SelectedMovie.Title, itemNumber, MoviesToAdd.Count));

                                MovieInfo movieInfo = importFile.SelectedMovie.MovieInfo;
                                movieInfo.Picture = File.Exists(movieInfo.PictureFileName) ? Convert.ToBase64String(File.ReadAllBytes(movieInfo.PictureFileName)) : null;
                                movieInfo.AddFile(importFile.File);

                                worker.OnProgress(GetPercent(step++), string.Format(ResourceUtils.GetString("filesImport", 17), importFile.SelectedMovie.Title, itemNumber, MoviesToAdd.Count));

                                movieService.InsertMovieInfo(movieInfo);
                                realAdded++;

                                worker.OnProgress(GetPercent(step), string.Format(ResourceUtils.GetString("filesImport", 17), importFile.SelectedMovie.Title, itemNumber, MoviesToAdd.Count));
                            }
                            itemNumber++;
                        }
                    }
                    return string.Format(ResourceUtils.GetString("filesImport", 18), realAdded);
                }
                catch (System.Exception e)
                {
                    log.Error(string.Format("Error adding movie, message: {0}", e.Message), e);
                    throw new MPMovieCatalogException(ResourceUtils.GetString("filesImport", 19), e);
                }
            }

            private int GetPercent(int itemNumber)
            {
                double percent = itemNumber;
                percent = percent / (MoviesToAdd.Count * 2) * 100.0;

                return int.Parse(Math.Floor(percent).ToString());
            }
        }
	}
}
